package seminar;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;

/**
 * A room with the lectures hold there
 * @author Johannes Degler
 *
 */
public class Room {

	private static final Logger log = Logger.getLogger(Room.class);

	private final LectureEvent events[][] = new LectureEvent[5][6]; //[Day][Slot]

	private final String description;

	/**
	 * New room<br>
	 * The constructor is hidden, use getRoomList instead
	 * @param description Room's description
	 */
	private Room(final String description){
		this.description = description;
	}

	/**
	 * Get a copy of the list of rooms
	 * @return List of rooms
	 */
	public static Collection<Room> getRoomList(){
		final Set<Room> rooms = new HashSet<Room>();
		rooms.add(new Room("1"));
		rooms.add(new Room("2"));
		rooms.add(new Room("3"));
		rooms.add(new Room("4"));
		rooms.add(new Room("5"));
		rooms.add(new Room("6"));
		return rooms;
	}

	/**
	 * Add an event to a specified day and slot
	 * @param day Day
	 * @param slot Slot
	 * @param event Event
	 */
	public void addEvent(final int day, final int slot, final LectureEvent event){
		Room.log.debug("Adding event " + event.getLecture() + " to room " + this.description + " on day " + day + ", slot " + slot);
		if(day >= 5 || slot >= 6)
			throw new IllegalArgumentException("Invalid day or slot");
		else if(this.isFree(day, slot))
			this.events[day][slot] = event;
		else
			throw new IllegalArgumentException("Room \"" + this.description + "\" is already in use");
	}

	/**
	 * Add an event to a specified day and slot
	 * @param point Point
	 * @param event Event
	 */
	public void addEvent(final Point point, final LectureEvent event){
		this.addEvent(point.x, point.y, event);
	}

	@Override
	public boolean equals(final Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (this.getClass() != obj.getClass())
			return false;
		final Room other = (Room) obj;
		if (this.description == null) {
			if (other.description != null)
				return false;
		} else if (!this.description.equals(other.description))
			return false;
		if (!Arrays.equals(this.events, other.events))
			return false;
		return true;
	}

	/**
	 * Get the room's description
	 * @return Room's description
	 */
	public String getDescription() {
		return this.description;
	}

	/**
	 * Get the rooms lecture events
	 * @return Lecture events
	 */
	public LectureEvent[][] getEvents() {
		return this.events;
	}

	/**
	 * Get a free point (day + slot)
	 * @param cEvents List of events the point must not collide with
	 * @return A free point
	 * @throws DistributionException Thrown if no free point is left
	 */
	public Point getFreePoint(final LectureEvent cEvents[][]) throws DistributionException{
		Room.log.debug("Searching for a free point in room " + this.description);
		final List<Point> possiblePoints = new ArrayList<Point>();
		for(int day = 0; day < 5; day++)
			for(int slot = 0; slot < 6; slot++)
				if(cEvents[day][slot] == null && this.events[day][slot] == null)
					possiblePoints.add(new Point(day, slot));

		if(possiblePoints.isEmpty())
			throw new DistributionException("No matching free points left");

		return possiblePoints.get((int)(Math.random() * possiblePoints.size()));
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime
				* result
				+ (this.description == null ? 0 : this.description.hashCode());
		result = prime * result + Arrays.hashCode(this.events);
		return result;
	}


	/**
	 * Is the room free at this day and slot
	 * @param day Day
	 * @param slot Slot
	 * @return True if the room is free
	 */
	private boolean isFree(final int day, final int slot){
		return this.events[day][slot] == null;
	}

	/**
	 * Is a free point left
	 * @param cEvents List of events the point must not collide with
	 * @return True if the room is free
	 */
	public boolean isFreePointLeft(final LectureEvent cEvents[][]){
		Room.log.debug("Testing if a free point is left in room " + this.description);
		for(int day = 0; day < 5; day++)
			for(int slot = 0; slot < 6; slot++)
				if(cEvents[day][slot] == null && this.events[day][slot] == null)
					return true;
		return false;
	}

	@Override
	public String toString() {
		return "Room " + this.description;
	}
}
